package mac5789.projeto4.experiment;

import static java.lang.String.valueOf;
import static org.apache.commons.lang.StringUtils.leftPad;

import java.math.BigDecimal;
import java.math.RoundingMode;

import mac5789.projeto4.algorithm.RTDPMDP;
import mac5789.projeto4.algorithm.ValueIterationMDP;
import mac5789.projeto4.model.Policy;
import mac5789.projeto4.model.State;
import mac5789.projeto4.model.WorldModel;
import mac5789.projeto4.parser.WorldModelParser;

/**
 * Experimento principal do projeto
 * 
 * @author lundberg
 * 
 */
public class ProjectExperiment {

	private static final double ACCEPTABLE_BELLMAN_ERROR = 0.01;

	public static void main(String... args) {
		new ProjectExperiment().run();
	}

	private void run() {
		this.solve("/mdpsGerados/m34.txt", ACCEPTABLE_BELLMAN_ERROR);
		this.solve("/mdpsGerados/m1314.txt", ACCEPTABLE_BELLMAN_ERROR);
		this.solve("/mdpsGerados/m2324.txt", ACCEPTABLE_BELLMAN_ERROR);
		this.solve("/mdpsGerados/m3334.txt", ACCEPTABLE_BELLMAN_ERROR);
		this.solve("/mdpsGerados/m4344.txt", ACCEPTABLE_BELLMAN_ERROR);
		this.solve("/mdpsGerados/m5354.txt", ACCEPTABLE_BELLMAN_ERROR);
		this.solve("/mdpsGerados/m6364.txt", ACCEPTABLE_BELLMAN_ERROR);
		this.solve("/mdpsGerados/m7374.txt", ACCEPTABLE_BELLMAN_ERROR);
		this.solve("/mdpsGerados/m8384.txt", ACCEPTABLE_BELLMAN_ERROR);
		this.solve("/mdpsGerados/m9394.txt", ACCEPTABLE_BELLMAN_ERROR);
		this.solve("/mdpsGerados/m103104.txt", ACCEPTABLE_BELLMAN_ERROR);
	}

	private void solve(String inputPath, double acceptableError) {
		WorldModel world = new WorldModelParser(this.getClass().getResourceAsStream(inputPath)).parse();
		// ((DeclarableWorldModel) world).withDiscountFactor(0.95);
		ValueIterationMDP vi = new ValueIterationMDP(acceptableError);
		long viStart = System.nanoTime();
		Policy viPolicy = vi.createPolicy(world);
		long viEnd = System.nanoTime();

		RTDPMDP rtdp = new RTDPMDP(acceptableError);
		long rtdpStart = System.nanoTime();
		Policy rtdpPolicy = rtdp.createPolicy(world);
		long rtdpEnd = System.nanoTime();

		int rtdpPolicySize = 0;
		int policyDivergencies = 0;
		for (State state : world.states()) {
			if (rtdpPolicy.whatToDoGiven(state) != null) {
				rtdpPolicySize++;
				if (!rtdpPolicy.whatToDoGiven(state).equals(viPolicy.whatToDoGiven(state))) {
					policyDivergencies++;
				}
			}
		}
		System.out.println("States: " + leftPad(valueOf(world.states().size()), 30));
		System.out.println("VI Time: " + leftPad(toSeconds(viEnd - viStart), 29));
		System.out.println("VI Iteractions: " + leftPad(valueOf(vi.getIteractions()), 22));
		System.out.println("RTDP Time: " + leftPad(toSeconds(rtdpEnd - rtdpStart), 27));
		System.out.println("RTDP Iteractions: " + leftPad(valueOf(rtdp.getIteractions()), 20));
		System.out.println("RTDP Policy Size: " + leftPad(valueOf(rtdpPolicySize), 20));
		System.out.println("Policy Divergencies: " + leftPad(valueOf(policyDivergencies), 17));
		System.out.println("\n\n\n\n\n");
	}

	private String toSeconds(long nanoseconds) {
		return new BigDecimal(nanoseconds).divide(new BigDecimal("1000000")).setScale(3, RoundingMode.HALF_EVEN).toPlainString();
	}
}
